package com.think.cloud.thinkshop.mall.service.coupon.impl;


import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.think.cloud.thinkshop.mall.controller.app.coupon.dto.CartCouponDTO;
import com.think.cloud.thinkshop.mall.controller.app.coupon.vo.AppUserCouponRespVO;
import com.think.cloud.thinkshop.mall.controller.app.coupon.vo.CartCouponDetailRespVO;
import com.think.cloud.thinkshop.mall.controller.app.coupon.vo.CartCouponRespVO;
import com.think.cloud.thinkshop.mall.convert.coupon.ProductCouponConvert;
import com.think.cloud.thinkshop.mall.domain.coupon.ProductCoupon;
import com.think.cloud.thinkshop.mall.domain.coupon.ProductCouponRelation;
import com.think.cloud.thinkshop.mall.enums.common.CommonWhetherEnum;
import com.think.cloud.thinkshop.mall.enums.coupon.*;
import com.think.cloud.thinkshop.mall.mapper.coupon.ProductCouponMapper;
import com.think.cloud.thinkshop.mall.mapper.coupon.ProductCouponRelationMapper;
import com.think.cloud.thinkshop.mall.service.coupon.AppProductCouponRelationService;
import com.think.common.core.exception.enums.ErrorCode;
import com.think.common.core.exception.util.ServiceExceptionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商品优惠券关联AppService业务层处理
 *
 * @author zkthink
 * @date 2024-05-21
 */
@Service
public class AppProductCouponRelationServiceImpl implements AppProductCouponRelationService {
    @Autowired
    private ProductCouponRelationMapper productCouponRelationMapper;

    @Autowired
    private ProductCouponMapper productCouponMapper;

    private ProductCoupon getCouponById(Long id){
        return productCouponMapper.selectById(id);
    }

    @Override
    public void receiveCoupon(Long id, Long userId,Integer num,Long planId) {
        // 查询优惠券
        ProductCoupon coupon = getCouponById(id);
        if (coupon == null) throw ServiceExceptionUtil.exception(ErrorCode.PRODUCT_COUPON_NOT_EXISTS);
        if (coupon.getNumber() - coupon.getReceivedNumber() < num)
            throw ServiceExceptionUtil.exception(ErrorCode.NOT_PRODUCT_COUPON_ERROR);
        //校验已领取数量
        long count = getReceivedCount(id, userId);
        if (CouponReceiveTypeEnum.UNLIMITED.getValue().equals(coupon.getReceiveType())
                || count + num <= coupon.getLimitNumber()) {
            List<ProductCouponRelation> relationDOList = new ArrayList<>();
            for (int i = 0; i < num; i++) {
                ProductCouponRelation relationDO = ProductCouponRelation.builder()
                        .couponId(id)
                        .userId(userId)
                        .receiveTime(Timestamp.valueOf(LocalDateTime.now()))
                        .planId(planId)
                        .build();
                relationDOList.add(relationDO);
            }
            Db.saveBatch(relationDOList);
            updateCouponById(ProductCoupon.builder().id(coupon.getId())
                    .receivedNumber(coupon.getReceivedNumber() + num).build());
        } else {
            throw ServiceExceptionUtil.exception(ErrorCode.PRODUCT_COUPON_RECEIVE_ERROR);
        }
    }

    private void updateCouponById(ProductCoupon coupon){
        productCouponMapper.updateById(coupon);
    }

    @Override
    public void redeem(String couponCode, Long userId) {
        // 查询优惠券
        ProductCoupon coupon =
                productCouponMapper.selectOne(new LambdaQueryWrapper<ProductCoupon>().eq(ProductCoupon::getCouponCode, couponCode));
        if (coupon == null) throw ServiceExceptionUtil.exception(ErrorCode.PRODUCT_COUPON_NOT_EXISTS);
        if (coupon.getNumber() - coupon.getReceivedNumber() < 1)
            throw ServiceExceptionUtil.exception(ErrorCode.NOT_PRODUCT_COUPON_ERROR);
        long count = getReceivedCount(coupon.getId(), userId);
        if (CouponReceiveTypeEnum.UNLIMITED.getValue().equals(coupon.getReceiveType())
                || count < coupon.getLimitNumber()) {
            ProductCouponRelation relationDO = ProductCouponRelation.builder().couponId(coupon.getId()).userId(userId).build();
            relationDO.setReceiveTime(Timestamp.valueOf(LocalDateTime.now()));
            productCouponRelationMapper.insert(relationDO);
            updateCouponById(ProductCoupon.builder().id(coupon.getId())
                    .receivedNumber(coupon.getReceivedNumber() + 1).build());
        } else {
            throw ServiceExceptionUtil.exception(ErrorCode.PRODUCT_COUPON_RECEIVE_ERROR);
        }
    }


    public long getReceivedCount(Long id, Long userId) {
        return productCouponRelationMapper.selectCount(new LambdaQueryWrapper<ProductCouponRelation>()
                .eq(ProductCouponRelation::getCouponId, id).eq(ProductCouponRelation::getUserId, userId));
    }

    @Override
    public Long getCouponUserCount(Long planId, DateTime start, DateTime end) {
        return productCouponRelationMapper.getCouponUserCount(planId, start, end);
    }

    @Override
    public ProductCouponRelation getById(Long id) {
        return productCouponRelationMapper.selectById(id);
    }

    @Override
    public void verificationCoupon(Long id) {
        ProductCouponRelation couponRelation = getById(id);
        if (couponRelation == null) {
            // throw exception(PRODUCT_COUPON_NOT_EXISTS);
        }
        // 使用优惠券
        couponRelation.setIsUsed(CouponIsUsedEnum.USED.getValue());
        couponRelation.setUsageTime(Timestamp.valueOf(LocalDateTime.now()));
        productCouponRelationMapper.updateById(couponRelation);
    }

    @Override
    public void returnCoupon(Long id) {
        // 重置优惠券状态
        productCouponRelationMapper.update(null, new LambdaUpdateWrapper<ProductCouponRelation>()
                .set(ProductCouponRelation::getIsUsed, CommonWhetherEnum.NO.getValue())
                .set(ProductCouponRelation::getUsageTime, null)
                .eq(ProductCouponRelation::getId, id));
    }

    @Override
    public List<AppUserCouponRespVO> searchUserCoupon(Integer type, Long id, Long userId) {
        List<AppUserCouponRespVO> userCouponVOS = productCouponRelationMapper.searchUserCoupon(type, userId, id);
        for (AppUserCouponRespVO userCouponVO : userCouponVOS) {
            if (CouponExpirationEnum.BY_DAY.getValue().equals(userCouponVO.getExpirationType())) {
                // 计算失效时间
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(userCouponVO.getReceiveTime());
                // 增加天数
                calendar.add(Calendar.DAY_OF_MONTH, userCouponVO.getExpirationDay().intValue());
                // 获取增加天数后的Timestamp
                Timestamp expirationTime = new Timestamp(calendar.getTime().getTime());
                userCouponVO.setTakingEffectTime(userCouponVO.getReceiveTime());
                userCouponVO.setExpirationTime(expirationTime);
            }
        }
        return userCouponVOS;
    }

    @Override
    public List<CartCouponRespVO> searchCartCoupon(List<CartCouponDTO> cartCouponDtoList, Long id, Long userId) {
        List<CartCouponRespVO> cartCouponVOList = new ArrayList<>();
        // 获取购物车中商品id集合
        Set<Long> productIds =
                cartCouponDtoList.stream().map(CartCouponDTO::getProductId).collect(Collectors.toSet());
        Map<Long, List<CartCouponDTO>> cartCouponDtoMap =
                cartCouponDtoList.stream().collect(Collectors.groupingBy(CartCouponDTO::getProductId));
        // 查询所有可使用的优惠券
        List<AppUserCouponRespVO> userCouponVOList = searchUserCoupon(CouponSearchTypeEnum.CAN_USE.getValue(), id, userId);
        if (CollectionUtils.isEmpty(userCouponVOList)) {
            return cartCouponVOList;
        }
        cartCouponVOList = ProductCouponConvert.INSTANCE.convertList1(userCouponVOList);
        // 过滤出可以使用的优惠券并计算优惠金额
        cartCouponVOList = cartCouponVOList.stream().filter(vo -> filter(productIds, vo, cartCouponDtoMap)).collect(Collectors.toList());
        // 优惠金额降序
        cartCouponVOList = cartCouponVOList.stream()
                .sorted(Comparator.comparing(CartCouponRespVO::getDiscountAmount).reversed()).collect(Collectors.toList());
        return cartCouponVOList;
    }

    @Override
    public List<Long> getProductIdList(Long id) {
        List<Long> productIdList = new ArrayList<>();
        ProductCouponRelation couponRelation = getById(id);
        ProductCoupon couponDO = getCouponById(couponRelation.getCouponId());
        if (CouponScopeEnum.PRODUCT.getValue().equals(couponDO.getCouponScope())) {
            for (String s : couponDO.getScopeValues().split(",")) productIdList.add(Long.parseLong(s));
        }
        return productIdList;
    }

    @Override
    public Integer getCouponNumber(Long userId) {
        return productCouponRelationMapper.getCouponNumber(userId);
    }


    /**
     * 过滤出可以使用的优惠券
     *
     * @param productIds       商品id集合
     * @param cartCouponVO     优惠券信息
     * @param cartCouponDtoMap 金额map
     * @return 过滤标识
     */
    private Boolean filter(Set<Long> productIds, CartCouponRespVO cartCouponVO, Map<Long, List<CartCouponDTO>> cartCouponDtoMap) {
        if (CouponScopeEnum.PRODUCT.getValue().equals(cartCouponVO.getCouponScope())) {
            Set<Long> ids = new HashSet<>();
            for (String s : cartCouponVO.getScopeValues().split(",")) ids.add(Long.parseLong(s));
            // 取交集
            ids.retainAll(productIds);
            if (CollectionUtils.isEmpty(ids)) return false;
            return compute(ids, cartCouponVO, cartCouponDtoMap);
        } else {
            return compute(productIds, cartCouponVO, cartCouponDtoMap);
        }
    }

    /**
     * 计算优惠金额
     *
     * @param productIds       商品id集合
     * @param cartCouponVO     优惠券信息
     * @param cartCouponDtoMap 金额map
     * @return 过滤标识
     */
    private Boolean compute(Set<Long> productIds, CartCouponRespVO cartCouponVO, Map<Long, List<CartCouponDTO>> cartCouponDtoMap) {
        // 累计金额
        BigDecimal amount = BigDecimal.ZERO;
        for (Long id : productIds)
            amount = amount.add(cartCouponDtoMap.get(id).stream().map(CartCouponDTO::getPrice).reduce(BigDecimal::add).get());
        // 是否满足门槛
        if (amount.compareTo(cartCouponVO.getThreshold()) < 0) return Boolean.FALSE;
        boolean couponTypeFlag = CouponTypeEnum.FULL_REDUCTION.getValue().equals(cartCouponVO.getCouponType());
        // 计算优惠金额
        BigDecimal discountAmount = BigDecimal.ZERO;
        List<CartCouponDetailRespVO> detailVOList = new ArrayList<>();
        for (Long id : productIds) {
            BigDecimal productCoupon = null;
            for (CartCouponDTO cartCouponDto : cartCouponDtoMap.get(id)) {
                if (couponTypeFlag) {
                    // 优惠金额不可超出商品总价
                    if (amount.compareTo(cartCouponVO.getCouponValue()) < 0) {
                        productCoupon = cartCouponDto.getPrice();
                    } else {
                        productCoupon = cartCouponVO.getCouponValue().multiply(cartCouponDto.getPrice().divide(amount, BigDecimal.ROUND_HALF_UP));
                    }
                } else {
                    productCoupon = cartCouponDto.getPrice().subtract(cartCouponDto.getPrice().multiply(cartCouponVO.getDiscount()).divide(BigDecimal.TEN));
                }
                discountAmount = discountAmount.add(productCoupon);
                detailVOList.add(CartCouponDetailRespVO.builder().productId(id).skuId(cartCouponDto.getSkuId()).productCoupon(productCoupon).build());
            }
        }
        cartCouponVO.setDiscountAmount(discountAmount);
        cartCouponVO.setDetailVOList(detailVOList);
        return Boolean.TRUE;
    }


}
